#include <iostream>
#include <fstream>
#include <limits>  // 用于处理输入缓冲区的清理

// 引入protobuf自动生成的头文件，包含通讯录数据结构定义
#include "contacts.pb.h"

using namespace std;


//@brief 是 Doxygen 的标签，表示 “简要说明”。
//@param 是 Doxygen 的标签，表示 “函数参数说明”。

/**
 * @brief 向联系人信息对象中添加数据
 * @param people 指向待填充数据的PeopleInfo对象的指针
 */
void AddPeopleInfo(contacts2::PeopleInfo* people){
    cout << "-------------新增联系人-------------" << endl;
    
    // 读取联系人姓名
    cout << "请输入联系人姓名: ";
    string name;
    getline(cin, name);  // 使用getline可读取包含空格的完整姓名
    people->set_name(name);  // 调用protobuf生成的setter方法设置姓名
    
    // 读取联系人年龄
    cout << "请输入联系人年龄: ";
    int age;
    cin >> age;  // 读取整数年龄
    people->set_age(age);  // 设置年龄
    
    // 清理输入缓冲区中的残留换行符
    // cin.ignore(256,'\n');
    // numeric_limits<streamsize>::max()确保清空所有剩余字符
    cin.ignore(numeric_limits<streamsize>::max(), '\n');
    
    // 循环读取多个电话号码，直到用户输入空行为止
    for(int i=0; ; i++){
        cout << "请输入联系人电话: " << i+1 << "(只输入回车完成电话新增): ";
        string number;
        getline(cin, number);  // 读取电话号码
        
        // 如果用户输入空行，则退出循环，结束电话号码输入
        if(number.empty()){
            break;
        }
        
        // 调用protobuf生成的add_phone()方法添加新电话
        // 该方法会返回一个指向新创建的Phone对象的指针
        contacts2::PeopleInfo_Phone* phone = people->add_phone();
        phone->set_numbers(number);  // 设置电话号码



        cout << "选择此电话号码类型（1、移动电话   2、固定电话）： ";
        int type;
        cin >> type;
        // 清理输入缓冲区中的残留换行符
        // cin.ignore(256,'\n');
        // numeric_limits<streamsize>::max()确保清空所有剩余字符
        cin.ignore(numeric_limits<streamsize>::max(), '\n');

        switch (type)
        {
        case 1:
            phone->set_type(contacts2::PeopleInfo_Phone_PhoneType::PeopleInfo_Phone_PhoneType_MP);
            break;
        case 2:
            phone->set_type(contacts2::PeopleInfo_Phone_PhoneType::PeopleInfo_Phone_PhoneType_TEL);
            break;
        default:
            cout << "选择有误!!" << endl;
            break;
        }
    }

    contacts2::Address address;
    cout << "请输入联系人家庭住址：";
    string home_address;
    getline(cin,home_address); 
    address.set_home_address(home_address);
    cout << "请输入联系人单位住址：";
    string unit_address;
    getline(cin,unit_address); 
    address.set_unit_address(unit_address);
    // Address -> Any
    people->mutable_data()->PackFrom(address);//返回值是bool类型

    cout << "请选择其他联系方式（1、QQ  2、微信）：";
    int other_contact;
    cin >> other_contact;
    // 清理输入缓冲区中的残留换行符
    // cin.ignore(256,'\n');
    // numeric_limits<streamsize>::max()确保清空所有剩余字符
    cin.ignore(numeric_limits<streamsize>::max(), '\n');
    switch (other_contact)
    {
    case 1:
        {
            cout << "请输入联系人QQ号: ";
            string qq;
            getline(cin, qq);  // 读取QQ号
            people->set_qq(qq);  // 设置QQ号
        }
        break;
    case 2:
        {
            cout << "请输入联系人微信号: ";
            string wechat;
            getline(cin, wechat);  // 读取微信号
            people->set_wechat(wechat);  // 设置微信号
        }
        break;
    default:
        cout << "选择有误!!" << endl;
        break;
    }

    
    for(int i = 0; ; i++){
        cout << "请输入联系人备注类型: " << i+1 << "(只输入回车完成备注新增): ";
        string remark_type;
        getline(cin, remark_type);  // 读取备注类型
        
        // 如果用户输入空行，则退出循环，结束备注输入
        if(remark_type.empty()){
            break;
        }
        
        cout << "请输入联系人备注内容: ";
        string remark_content;
        getline(cin, remark_content);  // 读取备注内容
        
        // 使用protobuf的map功能设置备注信息
        people->mutable_remark()->insert({remark_type, remark_content});
    }


    cout << "-------------添加联系人成功-------------" << endl;
}

int main()
{
    // 验证protobuf库版本是否与编译时一致，确保兼容性
    GOOGLE_PROTOBUF_VERIFY_VERSION;

    // 创建通讯录主对象，用于存储所有联系人信息
    contacts2::Contacts contacts;

    // 尝试读取本地已存在的通讯录文件
    fstream input("contacts.bin", ios::in | ios::binary);
    if(!input){
        // 文件不存在时提示将创建新文件
        cout << "contacts.bin  not find, creat new file! " << endl;
    }else if(!contacts.ParseFromIstream(&input)){
        // 解析文件失败时输出错误信息并退出
        cerr << "parse error!" << endl;
        input.close();
        return -1;
    }

    // 关闭输入流，避免资源占用
    input.close();

    // 向通讯录中添加新联系人
    // add_contacts()方法会创建一个新的PeopleInfo对象并返回其指针
    AddPeopleInfo(contacts.add_contacts());

    // 打开文件用于写入更新后的通讯录数据
    // ios::out: 输出模式；ios::trunc: 若文件存在则清空；ios::binary: 二进制模式
    fstream output("contacts.bin", ios::out | ios::trunc | ios::binary);
    if(!contacts.SerializeToOstream(&output)){
        // 序列化并写入失败时处理
        cerr << "write error!" << endl;
        output.close();
        return -1;
    }

    // 提示写入成功并关闭输出流
    cout << "write success!" << endl;
    output.close();

    // 清理protobuf库分配的全局资源，适合在长时间运行的程序中使用
    google::protobuf::ShutdownProtobufLibrary();
    return 0;
}
